package top.hmtools.wxmp.core;

import java.io.InputStream;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.net.URI;
import java.util.HashMap;
import java.util.Map;

import org.apache.commons.lang3.StringUtils;
import org.apache.http.client.utils.URIBuilder;
import org.apache.http.entity.mime.MultipartEntityBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import top.hmtools.wxmp.core.annotation.WxmpApi;
import top.hmtools.wxmp.core.annotation.WxmpParam;
import top.hmtools.wxmp.core.configuration.WxmpConfiguration;
import top.hmtools.wxmp.core.httpclient.HmHttpClientTools;
import top.hmtools.wxmp.core.tools.Bean2MapTools;

/**
 * 缺省的微信公众号接口会话
 * @author HyboWork
 *
 */
public class DefaultWxmpSession extends WxmpSession {
	
	public DefaultWxmpSession(WxmpConfiguration config) {
		super(config);
	}

	private final Logger logger = LoggerFactory.getLogger(DefaultWxmpSession.class);

	@Override
	public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
		//获取当前被代理方法的注解
		WxmpApi wxmpApi = method.getAnnotation(WxmpApi.class);
		
		if(wxmpApi==null){
			throw new RuntimeException("当前被代理类要执行的方法没有被 top.hmtools.wxmp.core.annotation.WxmpApi 注解修饰");
		}
		
		if(StringUtils.isBlank(wxmpApi.uri())){
			throw new RuntimeException("uri 不能为空");
		}
		
		// 提取方法被调用时的参数（如果有的话）
		HashMap<String, Object> params = new HashMap<>();
		
		Parameter[] parameters = method.getParameters();
		if(parameters != null && parameters.length>0){
			for(int ii=0;ii<parameters.length;ii++){
				Object argValue = args[ii];//获取当前形参值
				Parameter param = parameters[ii];//获取当前形参描述
				WxmpParam wxmpParam = param.getAnnotation(WxmpParam.class);//获取当前形参注解
				if(wxmpParam == null){
//					continue;
					//没有形参注解的，作为Javabean处理
					Map<String, Object> paramMapTmp = Bean2MapTools.bean2MapPlus(argValue);
					params.putAll(paramMapTmp);
				}else{
					//有形参注解的，根据配置内容选择处理方式
					switch(wxmpParam.httpParamDataType()){
					case TEXT :
						params.put(wxmpParam.name(), String.valueOf(argValue));
						break;
					case FILE :
						params.put(wxmpParam.name(), argValue);
						break;
					case INPUTSTREAM :
						params.put(wxmpParam.name(), argValue);
						break;
					case JAVABEAN :
						Map<String, Object> paramMapTmp = Bean2MapTools.bean2MapPlus(argValue);
						params.putAll(paramMapTmp);
						break;
					case BYTE_ARRAY :
						params.put(wxmpParam.name(), argValue);
						break;
					default :
						params.put(wxmpParam.name(), String.valueOf(argValue));
					}

				}
				
				if(this.logger.isDebugEnabled()){
					this.logger.debug("当前 method是：{}， param 是：{}，name 是：{}，参数值 是：{}，注解配置的数据类型是：{}",method,param,wxmpParam == null ? null:wxmpParam.name(),argValue,wxmpParam!=null?wxmpParam.httpParamDataType():null);
				}
			}
		}
		
		//获取返回数据类型
		Class<?> returnType = method.getReturnType();
		
		// 提取api请求URL
		String apiURL = null;
		String apiURI = wxmpApi.uri();
		
		if(!apiURI.toLowerCase().startsWith("http://") && !apiURI.toLowerCase().startsWith("https://")){
			if(apiURI.indexOf(".") > apiURI.indexOf("/")){
				//以域名开头
				apiURL = "https://"+apiURI;
			}else{
				//以相对路径开头
				apiURL = "https://"+this.wxmpConfiguration.geteUrlServer().toString()+"/"+apiURI;
			}
		}else{
			//以http开头的完整URL
			apiURL = apiURI;
		}
		URIBuilder uriBuilder = new URIBuilder(apiURL);
		String accessTokenString = this.wxmpConfiguration.getForceAccessTokenString();
		if(accessTokenString == null || accessTokenString.trim().length()<1){
			accessTokenString = this.wxmpConfiguration.getAccessTokenHandle().getAccessTokenString();
		}
		uriBuilder.addParameter("access_token", accessTokenString);
		URI apiURIResult = uriBuilder.build();
		
		//执行http请求微信公众号服务器，进行信息交互
		switch (wxmpApi.httpMethods()) {
		case GET:
			if(returnType.isAssignableFrom(InputStream.class)){
				//返回类型是 inputStream 的子类的话，则直接返回响应数据流
				return HmHttpClientTools.httpGetReqParamRespInputStream(apiURIResult.toString(), params);
			}else if(returnType.isAssignableFrom(String.class)){
				//返回类型是 String 的子类的话，则直接返回响应数据流
				return HmHttpClientTools.httpGetReqParamRespString(apiURIResult.toString(), params);
			}else{
				//其它返回数据类型均使用json反序列化
				return HmHttpClientTools.httpGetReqParamRespJson(apiURIResult.toString(), params, returnType);
			}
		case POST:
			//按request body 数据形式 分类
			switch (wxmpApi.httpParamType()) {
			case BINARY_BODY:
				//TODO
				break;
			case FORM_DATA:
				//获取注解配置的请求参数自定义转换工具
				Class<? extends RequestParamConvert> convertClass = wxmpApi.convert();
				RequestParamConvert requestParamConvert = convertClass.newInstance();
				//将请求参数转换成文件httpclient用文件上传参数
				MultipartEntityBuilder multipartEntityBuilder = requestParamConvert.convert(params);
				return HmHttpClientTools.httpPostReqMultiFormRespJson(apiURIResult.toString(), multipartEntityBuilder,returnType);
//				if(!convertClass.equals(RequestParamConvertBlank.class)){
//				}
//				break;
			case FORM_DATA_URLENCODED:
				return HmHttpClientTools.httpPostReqFormRespJson(apiURIResult.toString(), params, returnType);
			case HTML_BODY:
				//TODO
				
				break;
			case JSON_BODY:
				return HmHttpClientTools.httpPostReqJsonRespJson(apiURIResult.toString(), params, returnType);
			case TEXT_BODY:
				//TODO
				
				break;
			case XML_BODY:
				
				break;
			default:
				break;
			}
			break;
		default:
			break;
		}
		
		return null;
	}

}
